package qnit.test.hibiernate.id;

/**
 * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
 * 时间+应用的workId+应用的内存的sequence
 * 
 * 
 * 在分布式系统中，需要生成全局UID的场合还是比较多的，twitter的snowflake解决了这种需求，
 * 实现也还是很简单的，除去配置信息，核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12位。
 * 该项目地址为：https://github.com/twitter/snowflake是用Scala实现的。
 * python版详见开源项目https://github.com/erans/pysnowflake。
 * 核心代码为其IdWorker这个类实现，其原理结构如下，我分别用一个0表示一位，用—分割开部分的作用：
 * 
 * 
 * 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---0000000000 00
 * 在上面的字符串中，第一位为未使用（实际上也可作为long的符号位），接下来的41位为毫秒级时间，
 * 然后5位datacenter标识位，5位机器ID（并不算标识符，实际是为线程标识），
 * 然后12位该毫秒内的当前毫秒内的计数，加起来刚好64位，为一个Long型。
 * 
 * 这样的好处是，整体上按照时间自增排序，并且整个分布式系统内不会产生ID碰撞（由datacenter和机器ID作区分），
 * 并且效率较高，经测试，snowflake每秒能够产生26万ID左右，完全满足需要。
 * 
 * 
 * @author yanjr
 */
public class IdWorker {
	private final static long twepoch = 1288834974657L;
	/**
	 *  机器标识位数
	 */
	private final static long workerIdBits = 5L;
	/**
	 *  数据中心标识位数
	 */
	private final static long datacenterIdBits = 5L;
	/**
	 *  机器ID最大值
	 */
	private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
	/**
	 *  数据中心ID最大值
	 */
	private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
	/**
	 *  毫秒内自增位
	 */
	private final static long sequenceBits = 12L;
	/**
	 *  机器ID偏左移12位
	 */
	private final static long workerIdShift = sequenceBits;
	/**
	 *  数据中心ID左移17位
	 */
	private final static long datacenterIdShift = sequenceBits + workerIdBits;
	/**
	 *  时间毫秒左移22位
	 */
	private final static long timestampLeftShift = sequenceBits + workerIdBits
			+ datacenterIdBits;

	private final static long sequenceMask = -1L ^ (-1L << sequenceBits);

	private static long lastTimestamp = -1L;

	private long sequence = 0L;
	private final long workerId;
	private final long datacenterId;

	public IdWorker(long workerId, long datacenterId) {
		if (workerId > maxWorkerId || workerId < 0) {
			throw new IllegalArgumentException(
					"worker Id can't be greater than %d or less than 0");
		}
		if (datacenterId > maxDatacenterId || datacenterId < 0) {
			throw new IllegalArgumentException(
					"datacenter Id can't be greater than %d or less than 0");
		}
		this.workerId = workerId;
		this.datacenterId = datacenterId;
	}

	public synchronized long nextId() {
		long timestamp = timeGen();
		if (timestamp < lastTimestamp) {
			try {
				throw new Exception(
						"Clock moved backwards.  Refusing to generate id for "
								+ (lastTimestamp - timestamp) + " milliseconds");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		if (lastTimestamp == timestamp) {
			// 当前毫秒内，则+1
			sequence = (sequence + 1) & sequenceMask;
			if (sequence == 0) {
				// 当前毫秒内计数满了，则等待下一秒
				timestamp = tilNextMillis(lastTimestamp);
			}
		} else {
			sequence = 0;
		}
		lastTimestamp = timestamp;
		// ID偏移组合生成最终的ID，并返回ID
		long nextId = ((timestamp - twepoch) << timestampLeftShift)
				| (datacenterId << datacenterIdShift)
				| (workerId << workerIdShift) | sequence;

		return nextId;
	}

	/**
	 * 获得大于 lastTimestamp 的时间
	 * @param lastTimestamp
	 * @return timestamp
	 */
	private long tilNextMillis(final long lastTimestamp) {
		long timestamp = this.timeGen();
		while (timestamp <= lastTimestamp) {
			timestamp = this.timeGen();
		}
		return timestamp;
	}

	/**
	 * 获得系统当前时间
	 * @return
	 */
	private long timeGen() {
		return System.currentTimeMillis();
	}
	
	public static void main(String[] args) {
		IdWorker id = new IdWorker(1, 2);
		System.out.println(id.timeGen());
		System.out.println(-1L ^ (-1L << sequenceBits));
		
		System.out.println( (2L+ 2) & sequenceMask);
	}
}
